package thread_collaboration;

import java.util.concurrent.*;
import java.util.concurrent.locks.*;


public class ConsumerProducer {
    private static Buffer buffer = new Buffer();

    public static void main(String[] args) {
        // 创建线程池（两个）
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(new ProducerTask());
        executor.execute(new ConsumerTask());
        executor.shutdown();
 }

    // 向缓冲区添加int的任务
    private static class ProducerTask implements Runnable {
        public void run() {
            try {
                int i = 1;
                while (true) {
                    System.out.println("Producer writes " + i);
                    buffer.write(i++);  // 添加一个值到缓冲区
                    // 让线程进入睡眠状态
                    Thread.sleep((int) (Math.random() * 10000));
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    // 从缓冲区读取和删除int的任务
    private static class ConsumerTask implements Runnable {
        public void run() {
            try {
                while (true) {
                    System.out.println("\t\t\tConsumer reads " + buffer.read());
                    // 线程进入睡眠
                    Thread.sleep((int) (Math.random() * 10000));
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    // 缓冲区内部类
    private static class Buffer {
        private static final int CAPACITY = 1;  // 缓冲区容量
        private java.util.LinkedList<Integer> queue = new java.util.LinkedList<>();
        // Create a new lock
        private static Lock lock = new ReentrantLock();

        // 创建两个条件
        private static Condition notEmpty = lock.newCondition();
        private static Condition notfull = lock.newCondition();

        public void write(int value) {
            lock.lock(); // 拿到锁
            try {
                while (queue.size() == CAPACITY) {
                    System.out.println("Wait for notFull condition");
                    notfull.await();
                }
                queue.offer(value);
                notEmpty.signal();  // 信号灯处于空置状态
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } finally {
                lock.unlock();  // 开锁
            }
        }

        public int read() {
            int value = 0;
            lock.lock();
            try {
                while (queue.isEmpty()) {
                    System.out.println("\t\t\tWait for notEmpty condition");
                    notEmpty.await();
                }

                value = queue.remove();
                notfull.signal();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } finally {
                lock.unlock();
                return value;
            }
        }
    }
}
